/**************************************************************************
Step 1. Include necessary header files such that the stuff your test logic needs is declared. 
Don't forget gtest.h, which declares the testing framework.                                                   
**************************************************************************/
#include <string.h>
#include <stdint.h>
#include <inttypes.h>

#include "gtest/gtest.h"
#include "include/pf_hash.h"
#include "include/pf_internal.h"

typedef struct intk_v
{
    uint64_t key;
    char* value;
}intk_v_t;

typedef struct strk_v
{
    char* key;
    char* value;
}strk_v_t;

/**************************************************************************
Step 2. Use test fixture to design your complex cases. 
You can add SetUp() to initialize the test data and 
TearDown() to clear the test data for common usage
Pls remember that when you using test fixture, need to use macro "TEST_F" instead of "TEST"                                                 
**************************************************************************/
class PfHashTest : public testing::Test 
{
    /* This SetUp() will be called before every TEST CASE which is marked by macro "TEST_F" */
    virtual void SetUp() 
    {

    }

    /* This TearDown will be called after every TEST CASE which is marked by macro "TEST_F" */
    virtual void TearDown() 
    {

    }

};

static int str_cmp(const void* n1, const void* n2)
{
    return strcmp((const char*)n1, (const char*)n2);
}


static int cb_f(void* arg, void* key_ptr, uint64_t key_num, void* value)
{
    PF_UNUSED(arg);
    PF_UNUSED(key_ptr);
    PF_UNUSED(key_num);
    PF_UNUSED(value);

    return 0;
}

static int cb_err_f(void* arg, void* key_ptr, uint64_t key_num, void* value)
{
    PF_UNUSED(arg);
    PF_UNUSED(key_ptr);
    PF_UNUSED(key_num);
    PF_UNUSED(value);

    return -1;
}

/***************************************************************************
Step 3. Use macro "TEST_F" to start your test case                                      
You can design your test case as the example
***************************************************************************/
TEST_F(PfHashTest, HashNumTest)
{
    /* Define the local variables */
    int ret              = -1;
    pf_hash_t* hash_t    = NULL;
    uint32_t bucket_size = 2;
    char* val_ptr        = NULL;
    uint32_t count       = 0;
    intk_v_t kv[]        = {
                           { 0, ""},
                           { 103, "bcd"},
                           { 8320238LL, "ayuwerwew9rwelyaewrwewcy"},
                           { 22297233LL, "ysouwerya-090(33242"},
                           { UINT64_MAX, "UINT64_Max^&#@!=-*ayuwerwew9rwelyaewrwewcy"},
                           { 6822083L, "ayouwerwey"},
                           { 332083L, "ayoue098(*"},
                           { 403L, "ayoue098(*"},
                           { 3923L, "3202aoue098(03"},
                           { 23L, "weyoue098werew"},
                           };
    uint32_t kv_count    = (uint32_t)PF_ARR_SIZE(kv);
    uint32_t i           = 0;
        

    /* initilize test data for this case */
    hash_t = pf_hash_create(NULL, NULL, bucket_size);
    EXPECT_NE((void*)NULL, hash_t);

    /* Call your function for test */
    /* Check the result */
    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint32_t)0, count);

    for(i = 0 ; i < kv_count; i++)
    {
        ret = pf_hash_insert_num(hash_t, kv[i].key, kv[i].value);
        EXPECT_EQ(0, ret);

        /* test case for duplicate key */
        ret = pf_hash_insert_num(hash_t, kv[i].key, kv[i].value);
        EXPECT_EQ(PF_EKEYREJECTED, ret);
    }
    
    count = pf_hash_count(hash_t);
    EXPECT_EQ(kv_count, count);

    for(i = 0 ; i < kv_count; i++)
    {
        val_ptr = (char*)pf_hash_find_num(hash_t, kv[i].key);
        EXPECT_STREQ(kv[i].value, val_ptr);
    }

    ret = pf_hash_for_each(hash_t, NULL, cb_f);
    EXPECT_EQ(0, ret);

    /* test case for  callback function return error */
    ret = pf_hash_for_each(hash_t, NULL, cb_err_f);
    EXPECT_EQ(-1, ret);

    ret = pf_hash_clear(hash_t);
    EXPECT_EQ(0, ret);

    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint64_t)0, count);

    /* test case for traversing empty hash */
    ret = pf_hash_for_each(hash_t, NULL, cb_f);
    EXPECT_EQ(0, ret);
    ret = pf_hash_for_each(hash_t, NULL, cb_err_f);
    EXPECT_EQ(0, ret);

    /* re-insert for next test */
    for(i = 0 ; i < kv_count; i++)
    {
        ret = pf_hash_insert_num(hash_t, kv[i].key, kv[i].value);
        EXPECT_EQ(0, ret);

    }

    for(i = 0 ; i < kv_count; i++)
    {
        val_ptr = (char*)pf_hash_erase_num(hash_t, kv[i].key);
        EXPECT_STREQ(kv[i].value, val_ptr);

        val_ptr = (char*)pf_hash_find_num(hash_t, kv[i].key);
        EXPECT_EQ((void*)NULL, val_ptr);

        val_ptr = (char*)pf_hash_erase_num(hash_t, kv[i].key);
        EXPECT_EQ((void*)NULL, val_ptr);
    }
    
    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint32_t)0, count);

    /* test case for clear empty hash */
    ret = pf_hash_clear(hash_t);
    EXPECT_EQ(0, ret);

    /* Clear the test data for this case */
    ret = pf_hash_destory(hash_t);
    EXPECT_EQ(0, ret);
}

TEST_F(PfHashTest, HashBKDRStrTest)
{
    /* Define the local variables */
    int ret              = -1;
    pf_hash_t* hash_t    = NULL;
    uint32_t bucket_size = 1024;
    char* val_ptr        = NULL;
    uint32_t count       = 0;
    strk_v_t kv[]        = {
                           { "", "empty string key"},
                           { "k1", "key1 value haha."},
                           { "EmptyValue's Key", ""},
                           { "long key for test case hahayowuerwe", "weyorweuryzwerwe97234234234234234324327^#"},
                           { "special-@#$@#97234sadhc<>oe.IOwerKey)(e", "3;ywer27^#"},
                           };
    uint32_t kv_count    = (uint32_t)PF_ARR_SIZE(kv);
    uint32_t i           = 0;
        

    /* initilize test data for this case */
    hash_t = pf_hash_create(pf_hash_BKDR_str, str_cmp, bucket_size);
    EXPECT_NE((void*)NULL, hash_t);

    /* Call your function for test */
    /* Check the result */
    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint32_t)0, count);

    for(i = 0 ; i < kv_count; i++)
    {
        ret = pf_hash_insert_ptr(hash_t, kv[i].key, kv[i].value);
        EXPECT_EQ(0, ret);

        /* test case for duplicate key */
        ret = pf_hash_insert_ptr(hash_t, kv[i].key, kv[i].value);
        EXPECT_EQ(PF_EKEYREJECTED, ret);
    }
    
    count = pf_hash_count(hash_t);
    EXPECT_EQ(kv_count, count);

    for(i = 0 ; i < kv_count; i++)
    {
        val_ptr = (char*)pf_hash_find_ptr(hash_t, kv[i].key);
        EXPECT_STREQ(kv[i].value, val_ptr);
    }

    ret = pf_hash_for_each(hash_t, NULL, cb_f);
    EXPECT_EQ(0, ret);

    ret = pf_hash_clear(hash_t);
    EXPECT_EQ(0, ret);

    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint64_t)0, count);

    /* test case for traversing empty hash */
    ret = pf_hash_for_each(hash_t, NULL, cb_f);
    EXPECT_EQ(0, ret);

    /* re-insert for next test */
    for(i = 0 ; i < kv_count; i++)
    {
        ret = pf_hash_insert_ptr(hash_t, kv[i].key, kv[i].value);
        EXPECT_EQ(0, ret);

    }

    for(i = 0 ; i < kv_count; i++)
    {
        val_ptr = (char*)pf_hash_erase_ptr(hash_t, kv[i].key);
        EXPECT_STREQ(kv[i].value, val_ptr);

        val_ptr = (char*)pf_hash_find_ptr(hash_t, kv[i].key);
        EXPECT_EQ((void*)NULL, val_ptr);

        val_ptr = (char*)pf_hash_erase_ptr(hash_t, kv[i].key);
        EXPECT_EQ((void*)NULL, val_ptr);
    }
    
    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint32_t)0, count);

    /* test case for clear empty hash */
    ret = pf_hash_clear(hash_t);
    EXPECT_EQ(0, ret);

    /* Clear the test data for this case */
    ret = pf_hash_destory(hash_t);
    EXPECT_EQ(0, ret);
}

TEST_F(PfHashTest, HashDJBStrTest)
{
    /* Define the local variables */
    int ret              = -1;
    pf_hash_t* hash_t    = NULL;
    uint32_t bucket_size = 7;
    char* val_ptr        = NULL;
    uint32_t count       = 0;
    strk_v_t kv[]        = {
                           { "", "empty string key"},
                           { "k1", "key1 value haha."},
                           { "EmptyValue's Key", ""},
                           { "long key for test case hahayowuerwe", "weyorweuryzwerwe97234234234234234324327^#"},
                           { "special-@#$@#97234sadhc<>oe.IOwerKey)(e", "3;ywer27^#"},
                           };
    uint32_t kv_count    = (uint32_t)PF_ARR_SIZE(kv);
    uint32_t i           = 0;
        

    /* initilize test data for this case */
    hash_t = pf_hash_create(pf_hash_DJB_str, str_cmp, bucket_size);
    EXPECT_NE((void*)NULL, hash_t);

    /* Call your function for test */
    /* Check the result */
    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint32_t)0, count);

    for(i = 0 ; i < kv_count; i++)
    {
        ret = pf_hash_insert_ptr(hash_t, kv[i].key, kv[i].value);
        EXPECT_EQ(0, ret);

        /* test case for duplicate key */
        ret = pf_hash_insert_ptr(hash_t, kv[i].key, kv[i].value);
        EXPECT_EQ(PF_EKEYREJECTED, ret);
    }
    
    count = pf_hash_count(hash_t);
    EXPECT_EQ(kv_count, count);

    for(i = 0 ; i < kv_count; i++)
    {
        val_ptr = (char*)pf_hash_find_ptr(hash_t, kv[i].key);
        EXPECT_STREQ(kv[i].value, val_ptr);
    }

    ret = pf_hash_for_each(hash_t, NULL, cb_f);
    EXPECT_EQ(0, ret);

    ret = pf_hash_clear(hash_t);
    EXPECT_EQ(0, ret);

    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint64_t)0, count);

    /* test case for traversing empty hash */
    ret = pf_hash_for_each(hash_t, NULL, cb_f);
    EXPECT_EQ(0, ret);

    /* re-insert for next test */
    for(i = 0 ; i < kv_count; i++)
    {
        ret = pf_hash_insert_ptr(hash_t, kv[i].key, kv[i].value);
        EXPECT_EQ(0, ret);

    }

    for(i = 0 ; i < kv_count; i++)
    {
        val_ptr = (char*)pf_hash_erase_ptr(hash_t, kv[i].key);
        EXPECT_STREQ(kv[i].value, val_ptr);

        val_ptr = (char*)pf_hash_find_ptr(hash_t, kv[i].key);
        EXPECT_EQ((void*)NULL, val_ptr);

        val_ptr = (char*)pf_hash_erase_ptr(hash_t, kv[i].key);
        EXPECT_EQ((void*)NULL, val_ptr);
    }
    
    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint32_t)0, count);

    /* test case for clear empty hash */
    ret = pf_hash_clear(hash_t);
    EXPECT_EQ(0, ret);

    /* Clear the test data for this case */
    ret = pf_hash_destory(hash_t);
    EXPECT_EQ(0, ret);
}

TEST_F(PfHashTest, HashSDBMStrTest)
{
    /* Define the local variables */
    int ret              = -1;
    pf_hash_t* hash_t    = NULL;
    uint32_t bucket_size = 1;
    char* val_ptr        = NULL;
    uint32_t count       = 0;
    strk_v_t kv[]        = {
                           { "", "empty string key"},
                           { "k1", "key1 value haha."},
                           { "EmptyValue's Key", ""},
                           { "long key for test case hahayowuerwe", "weyorweuryzwerwe97234234234234234324327^#"},
                           { "special-@#$@#97234sadhc<>oe.IOwerKey)(e", "3;ywer27^#"},
                           };
    uint32_t kv_count    = (uint32_t)PF_ARR_SIZE(kv);
    uint32_t i           = 0;
        

    /* initilize test data for this case */
    hash_t = pf_hash_create(pf_hash_SDBM_str, str_cmp, bucket_size);
    EXPECT_NE((void*)NULL, hash_t);

    /* Call your function for test */
    /* Check the result */
    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint32_t)0, count);

    for(i = 0 ; i < kv_count; i++)
    {
        ret = pf_hash_insert_ptr(hash_t, kv[i].key, kv[i].value);
        EXPECT_EQ(0, ret);

        /* test case for duplicate key */
        ret = pf_hash_insert_ptr(hash_t, kv[i].key, kv[i].value);
        EXPECT_EQ(PF_EKEYREJECTED, ret);
    }
    
    count = pf_hash_count(hash_t);
    EXPECT_EQ(kv_count, count);

    for(i = 0 ; i < kv_count; i++)
    {
        val_ptr = (char*)pf_hash_find_ptr(hash_t, kv[i].key);
        EXPECT_STREQ(kv[i].value, val_ptr);
    }

    ret = pf_hash_for_each(hash_t, NULL, cb_f);
    EXPECT_EQ(0, ret);

    ret = pf_hash_clear(hash_t);
    EXPECT_EQ(0, ret);

    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint64_t)0, count);

    /* test case for traversing empty hash */
    ret = pf_hash_for_each(hash_t, NULL, cb_f);
    EXPECT_EQ(0, ret);

    /* re-insert for next test */
    for(i = 0 ; i < kv_count; i++)
    {
        ret = pf_hash_insert_ptr(hash_t, kv[i].key, kv[i].value);
        EXPECT_EQ(0, ret);

    }

    for(i = 0 ; i < kv_count; i++)
    {
        val_ptr = (char*)pf_hash_erase_ptr(hash_t, kv[i].key);
        EXPECT_STREQ(kv[i].value, val_ptr);

        val_ptr = (char*)pf_hash_find_ptr(hash_t, kv[i].key);
        EXPECT_EQ((void*)NULL, val_ptr);

        val_ptr = (char*)pf_hash_erase_ptr(hash_t, kv[i].key);
        EXPECT_EQ((void*)NULL, val_ptr);
    }
    
    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint32_t)0, count);

    /* test case for clear empty hash */
    ret = pf_hash_clear(hash_t);
    EXPECT_EQ(0, ret);

    /* Clear the test data for this case */
    ret = pf_hash_destory(hash_t);
    EXPECT_EQ(0, ret);
}

TEST_F(PfHashTest, HashPJWStrTest)
{
    /* Define the local variables */
    int ret              = -1;
    pf_hash_t* hash_t    = NULL;
    uint32_t bucket_size = 128;
    char* val_ptr        = NULL;
    uint32_t count       = 0;
    strk_v_t kv[]        = {
                           { "", "empty string key"},
                           { "k1", "key1 value haha."},
                           { "EmptyValue's Key", ""},
                           { "long key for test case hahayowuerwe", "weyorweuryzwerwe97234234234234234324327^#"},
                           { "special-@#$@#97234sadhc<>oe.IOwerKey)(e", "3;ywer27^#"},
                           };
    uint32_t kv_count    = (uint32_t)PF_ARR_SIZE(kv);
    uint32_t i           = 0;
        

    /* initilize test data for this case */
    hash_t = pf_hash_create(pf_hash_PJW_str, str_cmp, bucket_size);
    EXPECT_NE((void*)NULL, hash_t);

    /* Call your function for test */
    /* Check the result */
    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint32_t)0, count);

    for(i = 0 ; i < kv_count; i++)
    {
        ret = pf_hash_insert_ptr(hash_t, kv[i].key, kv[i].value);
        EXPECT_EQ(0, ret);

        /* test case for duplicate key */
        ret = pf_hash_insert_ptr(hash_t, kv[i].key, kv[i].value);
        EXPECT_EQ(PF_EKEYREJECTED, ret);
    }
    
    count = pf_hash_count(hash_t);
    EXPECT_EQ(kv_count, count);

    for(i = 0 ; i < kv_count; i++)
    {
        val_ptr = (char*)pf_hash_find_ptr(hash_t, kv[i].key);
        EXPECT_STREQ(kv[i].value, val_ptr);
    }

    ret = pf_hash_for_each(hash_t, NULL, cb_f);
    EXPECT_EQ(0, ret);

    ret = pf_hash_clear(hash_t);
    EXPECT_EQ(0, ret);

    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint64_t)0, count);

    /* test case for traversing empty hash */
    ret = pf_hash_for_each(hash_t, NULL, cb_f);
    EXPECT_EQ(0, ret);

    /* re-insert for next test */
    for(i = 0 ; i < kv_count; i++)
    {
        ret = pf_hash_insert_ptr(hash_t, kv[i].key, kv[i].value);
        EXPECT_EQ(0, ret);

    }

    for(i = 0 ; i < kv_count; i++)
    {
        val_ptr = (char*)pf_hash_erase_ptr(hash_t, kv[i].key);
        EXPECT_STREQ(kv[i].value, val_ptr);

        val_ptr = (char*)pf_hash_find_ptr(hash_t, kv[i].key);
        EXPECT_EQ((void*)NULL, val_ptr);

        val_ptr = (char*)pf_hash_erase_ptr(hash_t, kv[i].key);
        EXPECT_EQ((void*)NULL, val_ptr);
    }
    
    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint32_t)0, count);

    /* test case for clear empty hash */
    ret = pf_hash_clear(hash_t);
    EXPECT_EQ(0, ret);

    /* Clear the test data for this case */
    ret = pf_hash_destory(hash_t);
    EXPECT_EQ(0, ret);
}

TEST_F(PfHashTest, HashELFStrTest)
{
    /* Define the local variables */
    int ret              = -1;
    pf_hash_t* hash_t    = NULL;
    uint32_t bucket_size = 65536;
    char* val_ptr        = NULL;
    uint32_t count       = 0;
    strk_v_t kv[]        = {
                           { "", "empty string key"},
                           { "k1", "key1 value haha."},
                           { "EmptyValue's Key", ""},
                           { "long key for test case hahayowuerwe", "weyorweuryzwerwe97234234234234234324327^#"},
                           { "special-@#$@#97234sadhc<>oe.IOwerKey)(e", "3;ywer27^#"},
                           };
    uint32_t kv_count    = (uint32_t)PF_ARR_SIZE(kv);
    uint32_t i           = 0;
        

    /* initilize test data for this case */
    hash_t = pf_hash_create(pf_hash_ELF_str, str_cmp, bucket_size);
    EXPECT_NE((void*)NULL, hash_t);

    /* Call your function for test */
    /* Check the result */
    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint32_t)0, count);

    for(i = 0 ; i < kv_count; i++)
    {
        ret = pf_hash_insert_ptr(hash_t, kv[i].key, kv[i].value);
        EXPECT_EQ(0, ret);

        /* test case for duplicate key */
        ret = pf_hash_insert_ptr(hash_t, kv[i].key, kv[i].value);
        EXPECT_EQ(PF_EKEYREJECTED, ret);
    }
    
    count = pf_hash_count(hash_t);
    EXPECT_EQ(kv_count, count);

    for(i = 0 ; i < kv_count; i++)
    {
        val_ptr = (char*)pf_hash_find_ptr(hash_t, kv[i].key);
        EXPECT_STREQ(kv[i].value, val_ptr);
    }

    ret = pf_hash_for_each(hash_t, NULL, cb_f);
    EXPECT_EQ(0, ret);

    ret = pf_hash_clear(hash_t);
    EXPECT_EQ(0, ret);

    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint64_t)0, count);

    /* test case for traversing empty hash */
    ret = pf_hash_for_each(hash_t, NULL, cb_f);
    EXPECT_EQ(0, ret);

    /* re-insert for next test */
    for(i = 0 ; i < kv_count; i++)
    {
        ret = pf_hash_insert_ptr(hash_t, kv[i].key, kv[i].value);
        EXPECT_EQ(0, ret);

    }

    for(i = 0 ; i < kv_count; i++)
    {
        val_ptr = (char*)pf_hash_erase_ptr(hash_t, kv[i].key);
        EXPECT_STREQ(kv[i].value, val_ptr);

        val_ptr = (char*)pf_hash_find_ptr(hash_t, kv[i].key);
        EXPECT_EQ((void*)NULL, val_ptr);

        val_ptr = (char*)pf_hash_erase_ptr(hash_t, kv[i].key);
        EXPECT_EQ((void*)NULL, val_ptr);
    }
    
    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint32_t)0, count);

    /* test case for clear empty hash */
    ret = pf_hash_clear(hash_t);
    EXPECT_EQ(0, ret);

    /* Clear the test data for this case */
    ret = pf_hash_destory(hash_t);
    EXPECT_EQ(0, ret);
}

TEST_F(PfHashTest, HashStrNullValTest)
{
    /* Define the local variables */
    int ret              = -1;
    pf_hash_t* hash_t    = NULL;
    char* key            = "NullValKey";
    char* val_ptr        = NULL;
    uint32_t bucket_size = 128; 
    uint32_t count       = 0;

    /* initilize test data for this case */
    hash_t = pf_hash_create(pf_hash_ELF_str, str_cmp, bucket_size);
    EXPECT_NE((void*)NULL, hash_t);

    /* Call your function for test */
    /* Check the result */
    ret = pf_hash_insert_ptr(hash_t, key, NULL);
    EXPECT_EQ(0, ret);

    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint32_t)1, count);

    val_ptr = (char*)pf_hash_find_ptr(hash_t, key);
    EXPECT_EQ((void*)NULL, val_ptr);

    ret = pf_hash_for_each(hash_t, NULL, cb_f);
    EXPECT_EQ(0, ret);

    val_ptr = (char*)pf_hash_erase_ptr(hash_t, key);
    EXPECT_EQ((void*)NULL, val_ptr);

    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint32_t)0, count);

    /* Clear the test data for this case */
    ret = pf_hash_destory(hash_t);
    EXPECT_EQ(0, ret);
}

#ifndef VALGRIND_CHECK /* Death test core dump makes valgrind too many errors */
TEST_F(PfHashTest, HashNumDeathTest)
{
    ::testing::FLAGS_gtest_death_test_style = "threadsafe"; /* avoid death warning */

    /* Define the local variables */
    int ret              = -1;
    pf_hash_t* hash_t    = NULL;
    char* val_ptr        = NULL;
    uint32_t bucket_size = 0; /* test case for bucket_size = = 0 */
    uint32_t count       = 0;

    /* initilize test data for this case */
    hash_t = pf_hash_create(NULL, NULL, bucket_size);
    EXPECT_NE((void*)NULL, hash_t);

    /* Call your function for test */
    /* Check the result */
    EXPECT_DEBUG_DEATH((ret = pf_hash_insert_num(NULL, 1, (void*)"")), "");
    EXPECT_DEBUG_DEATH((ret = pf_hash_insert_ptr(hash_t, (void*)"key", (void*)"")), "");

    EXPECT_DEBUG_DEATH((val_ptr = (char*)pf_hash_find_num(NULL, 1)), "");
    EXPECT_DEBUG_DEATH((val_ptr = (char*)pf_hash_find_ptr(hash_t, (void*)"key")), "");

    EXPECT_DEBUG_DEATH((val_ptr = (char*)pf_hash_erase_num(NULL, 1)), "");
    EXPECT_DEBUG_DEATH((val_ptr = (char*)pf_hash_erase_ptr(hash_t, (void*)"key")), "");

    EXPECT_DEBUG_DEATH((count = pf_hash_count(NULL)), "");

    EXPECT_DEBUG_DEATH((ret = pf_hash_clear(NULL)), "");

    EXPECT_DEBUG_DEATH((ret = pf_hash_for_each(NULL, NULL, cb_f)), "");
    EXPECT_DEBUG_DEATH((ret = pf_hash_for_each(hash_t, NULL, NULL)), "");

    /* Clear the test data for this case */
    EXPECT_DEBUG_DEATH((ret = pf_hash_destory(NULL)), "");

    ret = pf_hash_destory(hash_t);
    EXPECT_EQ(0, ret);
}

TEST_F(PfHashTest, HashStrDeathTest)
{
    ::testing::FLAGS_gtest_death_test_style = "threadsafe"; /* avoid death warning */

    /* Define the local variables */
    int ret              = -1;
    pf_hash_t* hash_t    = NULL;
    char* val_ptr        = NULL;
    uint32_t bucket_size = 0; /* test case for bucket_size = = 0 */
    uint32_t count       = 0;

    /* initilize test data for this case */
    hash_t = pf_hash_create(pf_hash_ELF_str, str_cmp, bucket_size);
    EXPECT_NE((void*)NULL, hash_t);

    /* Call your function for test */
    /* Check the result */
    EXPECT_DEBUG_DEATH((ret = pf_hash_insert_ptr(NULL, (void*)"key", (void*)"")), "");
    EXPECT_DEBUG_DEATH((ret = pf_hash_insert_ptr(hash_t, NULL, (void*)"")), "");

    EXPECT_DEBUG_DEATH((val_ptr = (char*)pf_hash_find_ptr(NULL, (void*)"key")), "");
    EXPECT_DEBUG_DEATH((val_ptr = (char*)pf_hash_find_ptr(hash_t, NULL)), "");

    EXPECT_DEBUG_DEATH((val_ptr = (char*)pf_hash_erase_ptr(NULL, (void*)"key")), "");
    EXPECT_DEBUG_DEATH((val_ptr = (char*)pf_hash_erase_ptr(hash_t, NULL)), "");

    EXPECT_DEBUG_DEATH((count = pf_hash_count(NULL)), "");

    EXPECT_DEBUG_DEATH((ret = pf_hash_clear(NULL)), "");

    EXPECT_DEBUG_DEATH((ret = pf_hash_for_each(NULL, NULL, cb_f)), "");
    EXPECT_DEBUG_DEATH((ret = pf_hash_for_each(hash_t, NULL, NULL)), "");

    /* Clear the test data for this case */
    EXPECT_DEBUG_DEATH((ret = pf_hash_destory(NULL)), "");

    ret = pf_hash_destory(hash_t);
    EXPECT_EQ(0, ret);
}
#endif /* #ifndef VALGRIND_CHECK */

#if 0 /* these test case need (512M * 24 + 4G * 24) = 108G memory & swap !!! */
TEST_F(PfHashTest, HashNumMaxNodeTest)
{
    /* Define the local variables */
    int ret              = -1;
    pf_hash_t* hash_t    = NULL;
    uint32_t bucket_size = 512 * 1024 * 1024;
    uint32_t count       = 0;
    uint32_t i           = 0;

    /* initilize test data for this case */
    hash_t = pf_hash_create(NULL, NULL, bucket_size);
    EXPECT_NE((void*)NULL, hash_t);

    /* Call your function for test */
    /* Check the result */
    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint32_t)0, count);

    for(i = 0 ; i < 0xffffffff; i++) /* HASHTAB_MAX_NODES */
    {
        ret = pf_hash_insert_num(hash_t, (uint64_t)i, (void*)"");
        EXPECT_EQ(0, ret);
    }
    
    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint32_t)0xffffffff, count);

    ret = pf_hash_insert_num(hash_t, (uint64_t)0xffffffff, (void*)"");
    EXPECT_EQ(PF_EDQUOT, ret);

    /* Clear the test data for this case */
    ret = pf_hash_destory(hash_t);
    EXPECT_EQ(0, ret);
}

TEST_F(PfHashTest, HashStrMaxNodeTest)
{
    /* Define the local variables */
    int ret              = -1;
    pf_hash_t* hash_t    = NULL;
    uint32_t bucket_size = 512 * 1024 * 1024;
    uint32_t count       = 0;
    uint32_t i           = 0;
    char buff[64]        = {0};

    /* initilize test data for this case */
    hash_t = pf_hash_create(pf_hash_SDBM_str, str_cmp, bucket_size);
    EXPECT_NE((void*)NULL, hash_t);

    /* Call your function for test */
    /* Check the result */
    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint32_t)0, count);

    for(i = 0 ; i < 0xffffffff; i++) /* HASHTAB_MAX_NODES */
    {
        snprintf( buff, sizeof(buff), "%"PRIu32, i);
        ret = pf_hash_insert_ptr(hash_t, buff, (void*)"");
        EXPECT_EQ(0, ret);
    }
    
    count = pf_hash_count(hash_t);
    EXPECT_EQ((uint32_t)0xffffffff, count);

    snprintf( buff, sizeof(buff), "%"PRIu32, (uint32_t)0xffffffff);
    ret = pf_hash_insert_ptr(hash_t, buff, (void*)"");
    EXPECT_EQ(PF_EDQUOT, ret);

    /* Clear the test data for this case */
    ret = pf_hash_destory(hash_t);
    EXPECT_EQ(0, ret);
}
#endif 
